home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / utmisc1 / chktex.lha / chktex / FindErrs.c < prev    next >
C/C++ Source or Header  |  1996-04-30  |  37KB  |  1,449 lines

  1. /*
  2.  *  ChkTeX v1.4, error searching & report routines.
  3.  *  Copyright (C) 1995-96 Jens T. Berger Thielemann
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  *  Contact the author at:
  20.  *              Jens Berger
  21.  *              Spektrumvn. 4
  22.  *              N-0666 Oslo
  23.  *              Norway
  24.  *              E-mail: <jensthi@ifi.uio.no>
  25.  *
  26.  *
  27.  */
  28.  
  29.  
  30. #include "ChkTeX.h"
  31.  
  32. #define INTFAULTMSG \
  33. "INTERNAL FAULT OCCURED! PLEASE SUBMIT A BUG REPORT!\n"
  34.  
  35. #ifndef __LOCALIZED
  36. char InternFault [] =   INTFAULTMSG;
  37. #       define INTERNFAULT      &InternFault[0]
  38. #else
  39. #       define INTERNFAULT      INTFAULTMSG
  40. #endif
  41.  
  42. STRPTR VerbClear = "|";
  43. BOOL    AtLetter = FALSE,  /* Whether `@' is a letter or not. */
  44.         InHeader = TRUE,   /* Whether we're in the header */
  45.         VerbMode = FALSE;  /* Whether we're in complete ignore-mode */
  46.  
  47. LONG    MathMode;  /* Whether we're in math mode or not    */
  48. STRPTR  VerbStr;   /* String we'll terminate verbmode upon */
  49.  
  50.  
  51. /***************************** ERROR MESSAGES ***************************/
  52.  
  53. struct ErrMsg LaTeXMsgs [emMaxFault + 1] =
  54. {
  55. {emMinFault,    etErr,  TRUE,   ctNone,
  56.      INTERNFAULT},
  57.  
  58. {emSpaceTerm,   etWarn, TRUE,   ctOutMath,
  59.      "Command terminated with space."},
  60.  
  61. {emNBSpace,     etWarn, TRUE,   ctNone,
  62.      "Non-breaking space (`~') should have been used."},
  63.  
  64. {emEnclosePar,  etWarn, TRUE,   ctInMath,
  65.      "You should enclose the previous parenthesis with `{}\'."},
  66.  
  67. {emItInNoIt,    etWarn, TRUE,   ctOutHead,
  68.      "Italic correction (`\\/') found in non-italic buffer."},
  69.  
  70. {emItDup,       etWarn, TRUE,   ctNone,
  71.      "Italic correction (`\\/') found more than once."},
  72.  
  73. {emNoItFound,   etWarn, TRUE,   ctOutHead,
  74.      "No italic correction (`\\/') found."},
  75.  
  76. {emAccent,      etWarn, TRUE,   ctNone,
  77.      "Accent command `%s' needs use of `\\%c%s'."},
  78.  
  79. {emWrongDash,   etWarn, TRUE,   ctOutMath,
  80.      "Wrong length of dash may have been used."},
  81.  
  82. {emExpectC,     etWarn, TRUE,   ctNone,
  83.      "`%s' expected, found `%s'."},
  84.  
  85. {emSoloC,       etWarn, TRUE,   ctNone,
  86.      "Solo `%s' found."},
  87.  
  88. {emEllipsis,    etWarn, TRUE,   ctNone,
  89.      "You should use %s to achieve an ellipsis."},
  90.  
  91. {emInterWord,   etWarn, TRUE,   ctOutMath,
  92.      "Interword spacing (`\\ ') should perhaps be used."},
  93.  
  94. {emInterSent,   etWarn, TRUE,   ctOutMath,
  95.      "Intersentence spacing (`\\@') should perhaps be used."},
  96.  
  97. {emNoArgFound,  etErr,  TRUE,   ctNone,
  98.      "Could not find argument for command."},
  99.  
  100. {emNoMatchC,    etWarn, TRUE,   ctOutMath,
  101.      "No match found for `%s'."},
  102.  
  103. {emMathStillOn, etWarn, TRUE,   ctNone,
  104.      "Mathmode still on at end of LaTeX file."},
  105.  
  106. {emNoMatchCC,   etWarn, TRUE,   ctNone,
  107.      "Number of `%c' doesn't match the number of `%c'!"},
  108.  
  109. {emUseQuoteLiga, etWarn, TRUE,  ctNone,
  110.      "Use either `` or '' as an alternative to `\"'."},
  111.  
  112. {emUseOtherQuote, etWarn, TRUE, ctNone,
  113.      "Use \"'\" (ASCII 39) instead  of \"´\" (ASCII 180)."},
  114.  
  115. {emUserWarn,    etWarn, TRUE,   ctNone,
  116.      "User-specified pattern found."},
  117.  
  118. {emNotIntended, etWarn, FALSE,  ctNone,
  119.      "This command might not be intended."},
  120.  
  121. {emComment,     etMsg,  FALSE,  ctNone,
  122.      "Comment displayed."},
  123.  
  124. {emThreeQuotes, etWarn, TRUE,   ctNone,
  125.      "Either %c\\,%c%c or %c%c\\,%c will look better."},
  126.  
  127. {emFalsePage,   etWarn, TRUE,   ctNone,
  128.      "Delete this space to maintain correct pagereferences."},
  129.  
  130. {emEmbrace,     etWarn, TRUE,   ctInMath,
  131.      "You might wish to put this between a pair of `{}'"},
  132.  
  133. {emSpacePunct,  etWarn, TRUE,   ctOutMath,
  134.      "You ought to remove spaces in front of punctuation."},
  135.  
  136. {emNoCmdExec,   etWarn, TRUE,   ctNone,
  137.      "Could not execute LaTeX command."},
  138.  
  139. {emItPunct,     etWarn, TRUE,   ctNone,
  140.      "Don't use \\/ in front of small punctuation."},
  141.  
  142. {emUseTimes,    etWarn, TRUE,   ctNone,
  143.      "$\\times$ may look prettier here."},
  144.  
  145. {emMultiSpace,  etWarn, FALSE,  ctOutMath,
  146.      "Multiple spaces detected in input."},
  147.  
  148. {emIgnoreText,  etWarn, TRUE,   ctNone,
  149.     "This text may be ignored."},
  150.  
  151. {emBeginQ,      etWarn, TRUE,   ctOutMath,
  152.    "Use ` to begin quotation, not '."},
  153.  
  154. {emEndQ,        etWarn, TRUE,   ctOutMath,
  155.    "Use ' to end quotation, not `."},
  156.  
  157. {emQuoteMix,    etWarn, TRUE,   ctNone,
  158.      "Don't mix quotes."},
  159.  
  160. {emWordCommand, etWarn, TRUE,   ctInMath,
  161.      "You should perhaps use `\\%s' instead."},
  162.  
  163. {emMaxFault,    etErr,  TRUE,   0,
  164.      INTERNFAULT}
  165.  
  166. };
  167.  
  168. struct ErrMsg PrgMsgs [pmMaxFault + 1] =
  169. {
  170. {pmMinFault,    etErr,  TRUE, 0,
  171.      INTERNFAULT},
  172.  
  173. {pmUnknownTerm, etErr,  TRUE, 0,
  174.      "Unknown terminal type - using normal verbosity."},
  175.  
  176. {pmNoFileMatch, etWarn, TRUE, 0,
  177.      "No files matched the pattern `%s'."},
  178. {pmNoTeXOpen,   etErr,  TRUE, 0,
  179.      "Unable to open the TeX file `%s'."},
  180.  
  181. {pmRename,      etMsg,  TRUE, 0,
  182.      "Renaming `%s' as `%s'."},
  183. {pmRenameErr,   etErr,  TRUE, 0,
  184.      "Could not rename `%s' to `%s'."},
  185.  
  186. {pmOutOpen,     etErr,  TRUE, 0,
  187.      "Unable to open output file."},
  188. {pmOutTwice,    etErr,  TRUE, 0,
  189.      "You can specify output file only once."},
  190.  
  191. {pmStrDupErr,   etErr,  TRUE, 0,
  192.      "Unable to duplicate strings - no memory?"},
  193. {pmWordListErr, etErr,  TRUE, 0,
  194.      "Unable to create wordlist - no memory?"},
  195. {pmNoStackMem,  etErr,  TRUE, 0,
  196.      "Unable to create stack - no memory?\n"},
  197.  
  198. {pmWarnNumErr,  etErr,  TRUE, 0,
  199.      "Illegal warning number used."},
  200. {pmVerbLevErr,  etErr,  TRUE, 0,
  201.      "Illegal verbosity level."},
  202.  
  203. {pmNotPSDigit,  etWarn, TRUE, 0,
  204.      "`%c' is not a %s digit - ignored!"},
  205. {pmEscCode,     etWarn, TRUE, 0,
  206.      "Unknown escape code `%c%c' - ignored!"},
  207.  
  208. {pmKeyWord,     etErr,  TRUE, 0,
  209.      "Unsupported control word (`%s') encountered in file `%s'."},
  210. {pmFaultFmt,    etErr,  TRUE, 0,
  211.      "\"%s\", line %d: Faulty format - unexpected %s found."},
  212. {pmRsrcOpen,    etWarn, TRUE, 0,
  213.      "Could not open `%s', may cause unwanted behaviour."},
  214.  
  215. {pmSlowAbbr,    etMsg,  FALSE, 0,
  216.      "The abbreviation `%s' requires slow abbreviation searching."},
  217.  
  218. {pmEmptyToken,  etErr,  TRUE,  0,
  219.      "Empty token isolated in `%s' - probably faulty format"},
  220.  
  221. {pmAssert,      etErr,  TRUE,  0,
  222.      "Assertion failed. Please report bug."},
  223.  
  224. {pmNoRsrc,      etWarn, TRUE, 0,
  225.      "Could not find global resource file."},
  226.  
  227. {pmMaxFault,    etErr,  TRUE, 0,
  228.      INTERNFAULT},
  229. };
  230.  
  231. /*
  232.  *  %b  - string to print Between fields (from -s option)
  233.  *  %c  - Column position of error
  234.  *  %d  - lenght of error (Digit)
  235.  *  %f  - current Filename
  236.  *  %i  - Turn on inverse printing mode.
  237.  *  %I  - Turn off inverse printing mode.
  238.  *  %k  - Kind of error (warning, error, message)
  239.  *  %l  - Line number of error
  240.  *  %m  - warning Message
  241.  *  %n  - warning Number
  242.  *  %u  - an Underlining line (like the one which appears when using -v1)
  243.  *  %r  - part of line in front of error ('S' - 1)
  244.  *  %s  - part of line which contains error (String)
  245.  *  %t  - part of line after error ('S' + 1)
  246.  */
  247.  
  248.  
  249. #define istex(c)        (isalpha(c) || (AtLetter && (c == '@')))
  250.  
  251. #define CTYPE(func) \
  252. static int my_##func(int c) \
  253. { \
  254.    return(func(c)); \
  255. }
  256.  
  257. #define INUSE(c)        (LaTeXMsgs[(enum ErrNum) c].InUse)
  258.  
  259. #define PSERRA(pos,len,err,a) \
  260.     PrintError(CurStkName(&InputStack), RealBuf, pos, len, Line, err, a);
  261.  
  262. #define HEREA(len, err, a)     PSERRA(BufPtr - Buf - 1, len, err, a)
  263. #define PSERR(pos,len,err)     PSERRA(pos,len,err,"")
  264. #define HERE(len, err)         HEREA(len, err, "")
  265.  
  266.  
  267. #define SKIP_BACK(ptr, c, check) \
  268.     while((c = *ptr--)) \
  269.     { \
  270.         ifn(check) \
  271.             break; \
  272.     } \
  273.     ptr++;
  274.  
  275. #define SKIP_AHEAD(ptr, c, check) \
  276.     while((c = *ptr++)) \
  277.     { \
  278.         ifn(check) \
  279.             break; \
  280.     } \
  281.     ptr--;
  282.  
  283.  
  284. /*  -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=-  */
  285.  
  286. static ULONG Line;
  287.  
  288. static STRPTR RealBuf, LineCpy, BufPtr;
  289.  
  290. NEWBUF(Buf, BUFSIZ);
  291. NEWBUF(CmdBuffer, BUFSIZ);
  292. NEWBUF(ArgBuffer, BUFSIZ);
  293.  
  294.  
  295. CTYPE(isdigit)
  296. CTYPE(isalpha)
  297.  
  298.  
  299. static STRPTR MakeCpy(void)
  300. {
  301.     if(!LineCpy)
  302.         LineCpy = strdup(RealBuf);
  303.  
  304.     if(!LineCpy)
  305.         PrintPrgErr(pmStrDupErr);
  306.  
  307.     return(LineCpy);
  308. }
  309.  
  310. static STRPTR PreProcess(void)
  311. {
  312.     /* First, kill comments. */
  313.  
  314.     STRPTR TmpPtr;
  315.  
  316.     strcpy(Buf, RealBuf);
  317.  
  318.     TmpPtr = Buf;
  319.  
  320.     while((TmpPtr = strchr(TmpPtr, '%')))
  321.     {
  322.         if(TmpPtr[-1] != '\\')
  323.         {
  324.             PSERR(TmpPtr - Buf, 1, emComment);
  325.             *TmpPtr = 0;
  326.             break;
  327.         }
  328.         TmpPtr++;
  329.     }
  330.     return(Buf);
  331. }
  332.  
  333. /*
  334.  * Interpret environments
  335.  */
  336.  
  337. static void PerformEnv(STRPTR Env, int Begin)
  338. {
  339. static
  340.     UBYTE   VBStr [BUFSIZ] = "";
  341.  
  342.     if(HasWord(Env, &MathEnvir))
  343.     {
  344.     MathMode += Begin ? 1 : -1;
  345.     MathMode = max(MathMode, 0);
  346.     }
  347.  
  348.     if(HasWord(Env, &VerbEnvir))
  349.     {
  350.         VerbMode = Begin;
  351.         sprintf(VBStr, "\\end{%s}", Env);
  352.         VerbStr = VBStr;
  353.     }
  354. }
  355.  
  356. static STRPTR SkipVerb(void)
  357. {
  358.     STRPTR TmpPtr = BufPtr;
  359.     int TmpC;
  360.  
  361.     if(VerbMode && BufPtr)
  362.     {
  363.         ifn(TmpPtr = strstr(BufPtr, VerbStr))
  364.             BufPtr = &BufPtr[strlen(BufPtr)];
  365.         else
  366.         {
  367.             VerbMode = FALSE;
  368.             BufPtr = &TmpPtr[strlen(VerbStr)];
  369.         SKIP_AHEAD(BufPtr, TmpC, LATEX_SPACE(TmpC));
  370.             if(*BufPtr)
  371.                 PSERR(BufPtr - Buf, strlen(BufPtr) - 2, emIgnoreText);
  372.         }
  373.     }
  374.     return(TmpPtr);
  375. }
  376.  
  377. #define CHECKDOTS(wordlist, dtval) \
  378. for(i = 0; (i < wordlist.Stack.Used) && !(Back && Front);  i++) \
  379.  { if(!strafter(PstPtr, wordlist.Stack.Data[i])) \
  380.      Back = dtval; \
  381.    if(!strinfront(PrePtr, wordlist.Stack.Data[i])) \
  382.      Front = dtval; }
  383.  
  384.  
  385.  
  386. /*
  387.  * Checks that the dots are correct 
  388.  */
  389.  
  390. static enum DotLevel CheckDots(STRPTR PrePtr, STRPTR PstPtr)
  391. {
  392.     ULONG i;
  393.     int TmpC;
  394.     enum DotLevel Front = dtUnknown, Back = dtUnknown;
  395.  
  396.     if(MathMode)
  397.     {
  398.     PrePtr--;
  399.     SKIP_BACK(PrePtr, TmpC, (LATEX_SPACE(TmpC) || strchr("{}", TmpC)));
  400.     SKIP_AHEAD(PstPtr, TmpC, (LATEX_SPACE(TmpC)|| strchr("{}", TmpC)));
  401.  
  402.     CHECKDOTS(CenterDots, dtCDots);
  403.  
  404.     ifn(Front && Back)
  405.     {
  406.         CHECKDOTS(LowDots, dtLDots);
  407.     }
  408.     return(Front & Back);
  409.     }
  410.     else
  411.     return(dtLDots);
  412.  
  413. }
  414.  
  415. static STRPTR Dot2Str(enum DotLevel dl)
  416. {
  417.     STRPTR Retval = INTERNFAULT;
  418.     switch(dl)
  419.     {
  420.     case dtUnknown:
  421.     Retval = "\\cdots or \\ldots";
  422.     break;
  423.     case dtDots:
  424.     Retval = "\\dots";
  425.     break;
  426.     case dtCDots:
  427.     Retval = "\\cdots";
  428.     break;
  429.     case dtLDots: 
  430.     Retval = "\\ldots";
  431.     break;
  432.     }
  433.     return Retval;
  434. }
  435.  
  436. /*
  437.  * Interpret isolated commands.
  438.  *
  439.  */
  440.  
  441. void PerformBigCmd(STRPTR CmdPtr)
  442. {
  443.     STRPTR  TmpPtr,
  444.             ArgEndPtr = GetLTXArg(BufPtr, ArgBuffer, '{'); /*}*/
  445.     ULONG   CmdLen = strlen(CmdBuffer);
  446.     UBYTE   TmpC;
  447.     enum ErrNum
  448.             ErrNum;
  449.     struct ErrInfo *ei;
  450.  
  451.     enum DotLevel dotlev, realdl = dtUnknown;
  452.  
  453.     /* Kill `\verb' commands */
  454.  
  455.     if(WipeVerb)
  456.     {
  457.         if(!strcmp(CmdBuffer, "\\verb"))
  458.         {
  459.             if(*BufPtr)
  460.             {
  461.                 if((TmpPtr = strchr(&BufPtr[1], *BufPtr)))
  462.             strwrite(CmdPtr, VerbClear, (TmpPtr - CmdPtr) + 1);
  463.                 else
  464.                     PSERR(CmdPtr - Buf, 5, emNoArgFound);
  465.             }
  466.         }
  467.     }
  468.  
  469.     if(HasWord(CmdBuffer, &IJAccent))
  470.     {
  471.         if(ArgEndPtr)
  472.         {
  473.             TmpPtr = ArgBuffer;
  474.             SKIP_AHEAD(TmpPtr, TmpC, TmpC == '{'); /* } */
  475.  
  476.             if(strchr("ij", *TmpPtr))
  477.             {
  478.                 if(TmpPtr[-1] != '\\')
  479.                     PrintError(CurStkName(&InputStack),  RealBuf,
  480.                                CmdPtr - Buf,
  481.                                (LONG) strlen(CmdBuffer), Line,
  482.                                emAccent, CmdBuffer,
  483.                    *TmpPtr, MathMode? "math" : "");
  484.             }
  485.         }
  486.         else
  487.             PSERR(CmdPtr - Buf, CmdLen, emNoArgFound);
  488.     }
  489.  
  490.     if(!strcmp(CmdBuffer, "\\begin") ||
  491.        !strcmp(CmdBuffer, "\\end"))
  492.     {
  493.         if(ArgEndPtr)
  494.         {
  495.             if(!strcmp(ArgBuffer, "document"))
  496.                 InHeader = FALSE;
  497.  
  498.             if(CmdBuffer[1] == 'b')
  499.             {
  500.                 ifn(PushErr(ArgBuffer, Line, CmdPtr - Buf,
  501.                             CmdLen, MakeCpy(),
  502.                             &EnvStack))
  503.                     PrintPrgErr(pmNoStackMem);
  504.             }
  505.             else
  506.             {
  507.                 if((ei = PopErr(&EnvStack)))
  508.                 {
  509.                     if(strcmp(ei->Data, ArgBuffer))
  510.                         PrintError(CurStkName(&InputStack), RealBuf,
  511.                                    CmdPtr - Buf,
  512.                                    (LONG) strlen(CmdBuffer),
  513.                                    Line, emExpectC, ei->Data, ArgBuffer);
  514.  
  515.                     FreeErrInfo(ei);
  516.                 }
  517.                 else
  518.                     PrintError(CurStkName(&InputStack), RealBuf,
  519.                                CmdPtr - Buf,
  520.                                (LONG) strlen(CmdBuffer),
  521.                                Line, emSoloC, ArgBuffer);
  522.             }
  523.  
  524.             PerformEnv(ArgBuffer, CmdBuffer[1] == 'b');
  525.         } else
  526.             PSERR(CmdPtr - Buf, CmdLen, emNoArgFound);
  527.     }
  528.  
  529.     if((ErrNum = PerformCommand(CmdBuffer, BufPtr)))
  530.         PSERR(CmdPtr - Buf, CmdLen, ErrNum);
  531.  
  532.     if(!strcmp(CmdBuffer, "\\cdots"))
  533.     realdl = dtCDots;
  534.  
  535.     if(!strcmp(CmdBuffer, "\\ldots"))
  536.     realdl = dtLDots;
  537.  
  538.     if(!strcmp(CmdBuffer, "\\dots"))
  539.     realdl = dtLDots;
  540.  
  541.     if(realdl != dtUnknown)
  542.     {
  543.     dotlev = CheckDots(CmdPtr, BufPtr);
  544.     if(dotlev && (dotlev != realdl))
  545.     {
  546.         TmpPtr = Dot2Str(dotlev);
  547.         PSERRA(CmdPtr - Buf, CmdLen, emEllipsis, TmpPtr);
  548.     }
  549.     }
  550.  
  551.     if(HasWord(CmdBuffer, &WipeArg))
  552.     {
  553.     if(*BufPtr == '[') /* ] */
  554.         ArgEndPtr = GetLTXArg(BufPtr, ArgBuffer, '['); /* [ */
  555.     else
  556.         ArgEndPtr = BufPtr;
  557.  
  558.     if(ArgEndPtr)
  559.             ArgEndPtr = GetLTXArg(ArgEndPtr, ArgBuffer, '{'); /* } */
  560.  
  561.     if(ArgEndPtr)
  562.         strwrite(BufPtr, VerbClear, ArgEndPtr - BufPtr);
  563.     else
  564.             PSERR(CmdPtr - Buf, CmdLen, emNoArgFound);
  565.     }
  566. }
  567.  
  568. /*
  569.  * Isolate & check abbreviations.
  570.  */
  571.  
  572. static void CheckAbbrevs(void)
  573. {
  574.     /* Search for abbrevs... */
  575.     ULONG Count, CmdLen;
  576.     int Char;
  577.     STRPTR TmpPtr, AbbPtr;
  578.  
  579.     if(INUSE(emInterWord))
  580.     {
  581.         BOOL HasAlpha = FALSE;
  582.  
  583.         strcpy(TmpBuffer, Buf);
  584.         strupr(TmpBuffer);
  585.  
  586.         for(Count = 0;
  587.             Count < SlowAbbrev.Stack.Used;
  588.             Count++)
  589.         {
  590.             for(AbbPtr = TmpBuffer;
  591.                 (AbbPtr = strstr(AbbPtr, SlowAbbrev.Stack.Data[Count]));
  592.                 AbbPtr++)
  593.             {
  594.                 CmdLen = strlen(SlowAbbrev.Stack.Data[Count]);
  595.                 Char = AbbPtr[CmdLen];
  596.                 if(LATEX_SPACE(Char))
  597.                         PrintError(CurStkName(&InputStack), RealBuf,
  598.                                    (AbbPtr - TmpBuffer) + CmdLen, 1, Line,
  599.                                    emInterWord);
  600.             }
  601.         }
  602.  
  603.         /*
  604.          * We define an abbrev to be any word (e.g. alphas separated with
  605.          * non-alpha characters) containing punctums. For instance:
  606.          * e.g. foo.bar.
  607.          *
  608.          * This will _not_ catch abbrevs like etc., so we'll
  609.          * keep the .chktexrc ABBREV keyword.
  610.          */
  611.  
  612.         Count = 0;         /* Amount of . in a word - 1 */
  613.         for(AbbPtr = TmpBuffer;
  614.             (Char = *AbbPtr++);
  615.             )
  616.         {
  617.             if(Char == '.')
  618.             {
  619.                  if(HasAlpha && LATEX_SPACE(*AbbPtr) && Count)
  620.              PSERR(AbbPtr - TmpBuffer, 1, emInterWord);
  621.                  Count++;
  622.             }
  623.             else if(!isalpha(Char))
  624.             {
  625.                 Count = 0;
  626.                 HasAlpha = FALSE;
  627.             }
  628.             else
  629.                 HasAlpha = TRUE;
  630.         }
  631.  
  632.  
  633.         /* First isolate abbrev, then hold it against table. */
  634.         /* NOTE - this modifies TmpBuffer! */
  635.  
  636.         TmpPtr = TmpBuffer;
  637.         for(AbbPtr = Buf;
  638.             (Char = *AbbPtr);
  639.             AbbPtr++)
  640.         {
  641.             if(isalpha(Char) || (Char == '.'))
  642.                 *TmpPtr++ = Char;
  643.             else
  644.             {
  645.                 *TmpPtr-- = 0;
  646.                 if(LATEX_SPACE(Char) && (*TmpPtr == '.'))
  647.                 {
  648.                     strupr(TmpBuffer);
  649.                     if(HasWord(TmpBuffer, &Abbrev))
  650.             PSERR(AbbPtr- Buf, 1, emInterWord);
  651.                 }
  652.  
  653.                 TmpPtr = TmpBuffer;
  654.             }
  655.         }
  656.     }
  657. }
  658.  
  659. /*
  660.  * Check misc. things which can't be included in the main loop.
  661.  *
  662.  */
  663.  
  664. static void CheckRest(void)
  665. {
  666.     ULONG Count;
  667.     LONG CmdLen;
  668.     STRPTR  UsrPtr;
  669.  
  670.     /* Search for user-specified warnings */
  671.  
  672.     if(INUSE(emUserWarn))
  673.     {
  674.         strcpy(TmpBuffer, Buf);
  675.  
  676.         for(Count = 0L;
  677.             Count < UserWarn.Stack.Used;
  678.             Count++)
  679.         {
  680.             for(UsrPtr = TmpBuffer;
  681.                 (UsrPtr = strstr(UsrPtr, UserWarn.Stack.Data[Count]));
  682.                 UsrPtr++)
  683.             {
  684.                 CmdLen = strlen(UserWarn.Stack.Data[Count]);
  685.         PSERR(UsrPtr - TmpBuffer, CmdLen, emUserWarn);
  686.             }
  687.         }
  688.     }
  689. }
  690.  
  691.  
  692. /* 
  693.  * Checks that the dash-len is correct.
  694.  */
  695.  
  696. static void CheckDash(void)
  697. {
  698.     STRPTR TmpPtr;
  699.     int TmpC;
  700.     LONG TmpCount, Len;
  701.     struct WordList *wl = NULL;
  702.     ULONG  i;
  703.     BOOL Errored = FALSE;
  704.     STRPTR PrePtr = &BufPtr[-2];
  705.  
  706.     TmpPtr = BufPtr;
  707.     SKIP_AHEAD(TmpPtr, TmpC, TmpC == '-');
  708.     TmpCount = TmpPtr - BufPtr + 1;
  709.  
  710.     if(MathMode)
  711.     {
  712.     if(TmpCount > 1)
  713.         HERE(TmpCount, emWrongDash);
  714.     }
  715.     else
  716.     {
  717.     if(LATEX_SPACE(*PrePtr) && LATEX_SPACE(*TmpPtr))
  718.         wl = &WordDash;
  719.     if(isdigit(*PrePtr) && isdigit(*TmpPtr))
  720.         wl = &NumDash;
  721.     if(isalpha(*PrePtr) && isalpha(*TmpPtr))
  722.         wl = &HyphDash;
  723.  
  724.     if(wl)
  725.     {
  726.         Errored = TRUE;
  727.         for(i = 0; i < wl->Stack.Used; i++)
  728.         {
  729.         Len = strtol(wl->Stack.Data[i], NULL, 0);
  730.         if(TmpCount == Len)
  731.         {
  732.             Errored = FALSE;
  733.             break;
  734.         }
  735.         }
  736.         if(Errored)
  737.         HERE(TmpCount, emWrongDash);
  738.     }
  739.     }
  740. }
  741.  
  742.  
  743.  
  744. /*
  745.  * Searches the `Buf' for possible errors, and prints the errors. `Line'
  746.  * is supplied for error printing.
  747.  */
  748.  
  749. BOOL FindErr(const STRPTR _RealBuf, const ULONG _Line)
  750. {
  751.   STRPTR
  752.     CmdPtr,   /* We'll have to copy each command out. */
  753.     PrePtr,   /* Ptr to char in front of command, NULL if
  754.                * the cmd appears as the first character  */
  755.     TmpPtr,   /* Temporary pointer */
  756.     ErrPtr;   /* Ptr to where an error started */
  757.  
  758.   UBYTE
  759.     TmpC,     /* Just a temp var used throughout the proc.*/
  760.     MatchC = 0,
  761.     Char;     /* Char. currently processed */
  762.   ULONG
  763.     BrOffset, /* Offset into BrOrder array */
  764.     CmdLen;   /* Length of misc. things */
  765.   BOOL MixingQuotes;
  766.  
  767.   int (*pstcb)(int c); 
  768.  
  769.   struct ErrInfo
  770.     *ei;
  771.  
  772. /*
  773.   static const     Characters we'll do some magic with
  774.     UBYTE MgcChars [] = "$\\{}[]()-^_\"´`\'.xX";
  775. */
  776.  
  777.   UBYTE
  778.     ABuf [2] = {0},
  779.     BBuf [2] = {0};
  780.  
  781.   enum DotLevel dotlev;
  782.  
  783.     LineCpy = NULL;
  784.  
  785.     if(_RealBuf)
  786.     {
  787.         RealBuf = _RealBuf;
  788.         Line = _Line;
  789.  
  790.         BufPtr = PreProcess();
  791.  
  792.         BufPtr = SkipVerb();
  793.  
  794.         while(BufPtr && *BufPtr)
  795.         {
  796.             PrePtr = BufPtr - 1;
  797.             switch(Char = *BufPtr++)
  798.             {
  799.             case 'X':
  800.             case 'x':
  801.                 TmpPtr = PrePtr;
  802.  
  803.                 SKIP_BACK(TmpPtr, TmpC,
  804.                     (LATEX_SPACE(TmpC) || strchr("{}$", TmpC)));
  805.  
  806.                 if(isdigit(*TmpPtr))
  807.                 {
  808.                     TmpPtr = BufPtr;
  809.  
  810.                     SKIP_AHEAD(TmpPtr, TmpC,
  811.                         (LATEX_SPACE(TmpC) || strchr("{}$", TmpC)));
  812.  
  813.                     if(isdigit(*TmpPtr))
  814.                         HERE(1, emUseTimes);
  815.                 }
  816.                 break;
  817.             case '.':
  818.                 if((Char == *BufPtr) && (Char == BufPtr[1]))
  819.         {
  820.             dotlev = CheckDots(&PrePtr[1], &BufPtr[2]);
  821.             TmpPtr = Dot2Str(dotlev);
  822.             HEREA(3, emEllipsis, TmpPtr);
  823.         }
  824.         if(!MathMode && islower(*PrePtr))
  825.         {
  826.             TmpPtr = BufPtr;
  827.             SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
  828.             if((TmpPtr != BufPtr) && islower(*TmpPtr))
  829.             PSERR(BufPtr - Buf, TmpPtr - BufPtr, emInterWord);
  830.         }
  831.         break;
  832.             case '\'':
  833.             case '`':
  834.                 if((Char == *BufPtr) && (Char == BufPtr[1]))
  835.                 {
  836.             PrintError(CurStkName(&InputStack), RealBuf,
  837.                    BufPtr - Buf - 1, 3, Line,
  838.                    emThreeQuotes,
  839.                    Char, Char, Char,
  840.                    Char, Char, Char);
  841.         }
  842.  
  843.         if(Char == '\'')
  844.             MatchC = '`';
  845.         else
  846.             MatchC = '\'';
  847.  
  848.          TmpPtr = BufPtr;
  849.         SKIP_AHEAD(TmpPtr, TmpC, TmpC == Char);
  850.  
  851.                 MixingQuotes = FALSE;
  852.  
  853.         if((*TmpPtr == MatchC) || (*TmpPtr == '\"') ||
  854.                    (*TmpPtr == '´'))
  855.                     MixingQuotes = TRUE;
  856.  
  857.         SKIP_AHEAD(TmpPtr, TmpC, strchr("`\'\"´", TmpC));
  858.  
  859.                 if(MixingQuotes)
  860.                 HERE(TmpPtr - BufPtr + 1, emQuoteMix);
  861.  
  862.         switch(Char)
  863.         {
  864.         case '\'':
  865.             if(isalpha(*TmpPtr) &&
  866.                (strchr(LATEX_PUNCT, *PrePtr) || isspace(*PrePtr)))
  867.             HERE(TmpPtr - BufPtr + 1, emBeginQ);
  868.             break;
  869.         case '`':
  870.             if(isalpha(*PrePtr) &&
  871.                (strchr(LATEX_PUNCT, *TmpPtr) || isspace(*TmpPtr)))
  872.             HERE(TmpPtr - BufPtr + 1, emEndQ);
  873.             break;
  874.         }
  875.         BufPtr = TmpPtr;
  876.                 break;
  877.             case '"':
  878.                 HERE(1, emUseQuoteLiga);
  879.                 break;
  880.  
  881.             case 180: /* ´ */
  882.                 HERE(1, emUseOtherQuote);
  883.                 break;
  884.  
  885.             case '_':
  886.             case '^':
  887.                 if(*PrePtr != '\\')
  888.                 {
  889.                     TmpPtr = PrePtr;
  890.                     SKIP_BACK(TmpPtr, TmpC, LATEX_SPACE(TmpC));
  891.  
  892.                     CmdLen = 1;
  893.  
  894.                     switch(TmpC)
  895.                     {
  896.                         /*{*/
  897.                     case '}':
  898.                         if(PrePtr[-1] != '\\')
  899.                             break;
  900.  
  901.                         CmdLen++;
  902.                         PrePtr--;
  903.                         /* FALLTHRU */
  904.                     /*[(*/
  905.                     case ')':
  906.                     case ']':
  907.                     case 0:
  908.                         PSERR(PrePtr - Buf, CmdLen, emEnclosePar);
  909.                     }
  910.  
  911.                     if((TmpPtr = strip(BufPtr, STRP_LFT)))
  912.                     {
  913.                         ErrPtr = TmpPtr;
  914.  
  915.                         if(isalpha(*TmpPtr))
  916.                             pstcb = &my_isalpha;
  917.                         elif(isdigit(*TmpPtr))
  918.                             pstcb = &my_isdigit;
  919.                         else
  920.                             break;
  921.  
  922.                         while((*pstcb)(*TmpPtr++))
  923.                             ;
  924.                         TmpPtr--;
  925.  
  926.                         if((TmpPtr - ErrPtr) > 1)
  927.                             PSERR(ErrPtr - Buf, TmpPtr - ErrPtr, emEmbrace);
  928.                     }
  929.                 }
  930.                 break;
  931.             case '-':
  932.         CheckDash();
  933.                 break;
  934.             case '\\':                    /* Command encountered  */
  935.                 CmdPtr = CmdBuffer;
  936.                 *CmdPtr++ = Char;
  937.                 *CmdPtr++ = Char = *BufPtr++;
  938.  
  939.                 if(istex(Char))
  940.                 {
  941.                     while(istex(Char))
  942.                         Char = *CmdPtr++ = *BufPtr++;
  943.  
  944.                     BufPtr--;
  945.                     CmdPtr--;
  946.                 }
  947.  
  948.                 *CmdPtr = 0;
  949.  
  950.                 /* We've now isolated the command */
  951.  
  952.                 if(LATEX_SPACE(*PrePtr))
  953.                 {
  954.                     if(HasWord(CmdBuffer, &Linker))
  955.                         PSERR(PrePtr - Buf, 1, emNBSpace);
  956.                     if(HasWord(CmdBuffer, &PostLink))
  957.                         PSERR(PrePtr - Buf, 1, emFalsePage);
  958.                 }
  959.  
  960.                 if(LATEX_SPACE(Char) && !MathMode && 
  961.            (!HasWord(CmdBuffer, &Silent)) &&
  962.            (strlen(CmdBuffer) != 2))
  963.                 {
  964.                     PSERR(BufPtr - Buf, 1, emSpaceTerm);
  965.                 }
  966.                 elif((*BufPtr == '\\') && (!isalpha(BufPtr[1])) && 
  967.              (!LATEX_SPACE(BufPtr[1])))
  968.                 {
  969.                     PSERR(BufPtr - Buf, 2, emNotIntended);
  970.                 }
  971.  
  972.                 PerformBigCmd(PrePtr + 1);
  973.                 BufPtr = SkipVerb();
  974.  
  975.                 break;
  976.                 /*{{*/
  977.             case '}':
  978.                 /* This should be implemented via the stacking below FIXME */
  979.  
  980.                 TmpPtr = BufPtr;
  981.                 while(*TmpPtr++ == '}')
  982.                     ;
  983.                 TmpPtr--;
  984.  
  985.                 if((*PrePtr != '\\') && !strchr(SMALL_PUNCT, *TmpPtr))
  986.                 {
  987.                     if(ItState == itOn)
  988.             PSERR(PrePtr - Buf + 1, 1,emNoItFound);
  989.                 }
  990.                 ItState = itOff;
  991.  
  992.                 /* FALLTHRU */
  993.             case '{': /* } */
  994.             case '(':
  995.             case '[':
  996.  
  997.             case ')':
  998.             case ']':
  999.                 AddBracket(Char);
  1000.  
  1001.                 if((BrOffset = BrackIndex(Char)) != ~0UL)
  1002.                 {
  1003.                     if(BrOffset & 1)      /* Closing bracket of some sort */
  1004.                     {
  1005.                         if((ei = PopErr(&CharStack)))
  1006.                         {
  1007.                             TmpC = MatchBracket(*(ei->Data));
  1008.                             FreeErrInfo(ei);
  1009.                         }
  1010.                         else
  1011.                             TmpC = 0;
  1012.  
  1013.                         if(TmpC != Char)
  1014.                         {
  1015.                             ABuf[0] = TmpC;
  1016.                             BBuf[0] = Char;
  1017.                             ABuf[1] = BBuf[1] = 0;
  1018.                             if(TmpC)
  1019.                                 PrintError(CurStkName(&InputStack), RealBuf,
  1020.                                            BufPtr - Buf - 1, 1, Line,
  1021.                                            emExpectC,
  1022.                                            ABuf, BBuf);
  1023.                             else
  1024.                 HEREA(1, emSoloC, BBuf);
  1025.                         }
  1026.  
  1027.                     }
  1028.                     else         /* Opening bracket of some sort  */
  1029.                     {
  1030.                         if(!LineCpy)
  1031.                             LineCpy = strdup(RealBuf);
  1032.  
  1033.                         if(LineCpy)
  1034.                         {
  1035.                             ifn(PushChar(Char, Line, PrePtr - Buf + 1,
  1036.                                          &CharStack, LineCpy))
  1037.                                 PrintPrgErr(pmNoStackMem);
  1038.                         }
  1039.                         else
  1040.                             PrintPrgErr(pmStrDupErr);
  1041.                     }
  1042.                 }
  1043.                 break;
  1044.             case '$':
  1045.                 if(*PrePtr != '\\')
  1046.                 {
  1047.                     if(*BufPtr == '$')
  1048.                         BufPtr++;
  1049.                     MathMode ^= TRUE;
  1050.                 }
  1051.  
  1052.                 break;
  1053.         default:
  1054.         if(isalpha(Char) && !isalpha(*PrePtr) && 
  1055.            (*PrePtr != '\\') && MathMode)
  1056.         {
  1057.             TmpPtr = BufPtr;
  1058.             CmdPtr = CmdBuffer;
  1059.             do
  1060.             {
  1061.             *CmdPtr++ = Char;
  1062.             Char = *TmpPtr++;
  1063.             } while(isalpha(Char));
  1064.             *CmdPtr = 0;
  1065.  
  1066.             if(HasWord(CmdBuffer, &MathRoman))
  1067.             HEREA(strlen(CmdBuffer), emWordCommand, CmdBuffer);
  1068.         }
  1069.  
  1070.         /*
  1071.          * Search for multiple spaces in input; space in front
  1072.          * of punctuation. 
  1073.          */
  1074.         
  1075.         if(LATEX_SPACE(Char))
  1076.         {
  1077.             TmpPtr = BufPtr;
  1078.             SKIP_AHEAD(TmpPtr, TmpC, LATEX_SPACE(TmpC));
  1079.  
  1080.             if(*TmpPtr)
  1081.             {
  1082.             if((TmpPtr - BufPtr) > 0)
  1083.             {
  1084.                 HERE(TmpPtr - BufPtr + 1, emMultiSpace);
  1085.                 strwrite(BufPtr, VerbClear, TmpPtr - BufPtr - 1);
  1086.             }
  1087.             }
  1088.             if(*BufPtr && strchr(LATEX_PUNCT, *BufPtr))
  1089.             HERE(2, emSpacePunct);
  1090.         }
  1091.  
  1092.         if(isupper(*PrePtr) && strchr(LATEX_PUNCT, Char) && 
  1093.            LATEX_SPACE(*BufPtr) && !LATEX_SPACE(PrePtr[-1]))
  1094.             HERE(1, emInterSent);
  1095.             }
  1096.         }
  1097.  
  1098.         if(!VerbMode)
  1099.         {
  1100.             CheckAbbrevs();
  1101.             CheckRest();
  1102.         }
  1103.     }
  1104.  
  1105.     return(TRUE);
  1106. }
  1107.  
  1108. /*
  1109.  * Prints the status/conclusion after doing all the testing, including
  1110.  * bracket stack status, math mode, etc.
  1111.  */
  1112.  
  1113. void PrintStatus(ULONG Lines)
  1114. {
  1115.   ULONG Cnt;
  1116.   struct ErrInfo *ei;
  1117.  
  1118.  
  1119.   while((ei = PopErr(&CharStack)))
  1120.   {
  1121.       PrintError(ei->File, ei->LineBuf, ei->Column,
  1122.                  ei->ErrLen, ei->Line, emNoMatchC,
  1123.                  (STRPTR) ei->Data);
  1124.       FreeErrInfo(ei);
  1125.   }
  1126.  
  1127.   while((ei = PopErr(&EnvStack)))
  1128.   {
  1129.       PrintError(ei->File, ei->LineBuf, ei->Column,
  1130.                  ei->ErrLen, ei->Line, emNoMatchC,
  1131.                  (STRPTR) ei->Data);
  1132.       FreeErrInfo(ei);
  1133.   }
  1134.  
  1135.   if(MathMode)
  1136.   {
  1137.       PrintError(CurStkName(&InputStack), "", 0L, 0L, Lines,
  1138.                  emMathStillOn);
  1139.   }
  1140.  
  1141.   for(Cnt = 0L; Cnt < (NUMBRACKETS>>1); Cnt++)
  1142.   {
  1143.       if(Brackets[Cnt << 1] != Brackets[(Cnt << 1) + 1])
  1144.       {
  1145.           PrintError(CurStkName(&InputStack), "", 0L, 0L, Lines,
  1146.                      emNoMatchCC,
  1147.                      BrOrder[Cnt<<1], BrOrder[(Cnt<<1) + 1]);
  1148.       }
  1149.   }
  1150.  
  1151.   if(!Quiet)
  1152.       fprintf(stderr,
  1153.               "%ld error(s) printed; %ld warning(s) printed; %ld user suppressed warnings.\n",
  1154.               ErrPrint, WarnPrint, UserSupp);
  1155. }
  1156.  
  1157.  
  1158. /*
  1159.  * Scans the `Buf' for a LaTeX arg, and puts that arg into `Dest'. `Delim'
  1160.  * is the leading character for the arg (either `{' or `[', that is).
  1161.  * Returns NULL if we can't find the argument, ptr to the first character
  1162.  * after the argument in other cases.
  1163.  *
  1164.  * Dest == NULL => we won't copy anything out.
  1165.  *
  1166.  */
  1167.  
  1168. STRPTR GetLTXArg(STRPTR Buf, STRPTR Dest, const UBYTE Delim)
  1169. {
  1170.     UBYTE       mileD, TmpC;
  1171.     STRPTR      Retval = NULL;
  1172.     ULONG       DeliCnt = 1,
  1173.     BufCnt = 0L;
  1174.  
  1175.     if(Dest)
  1176.         *Dest = 0;
  1177.  
  1178.     if((mileD = MatchBracket(Delim)))
  1179.     {
  1180.         Buf = strip(Buf, STRP_LFT);
  1181.  
  1182.         if((TmpC = *Buf) == Delim)
  1183.         {
  1184.             while(DeliCnt > 0L)
  1185.             {
  1186.                 TmpC = *++Buf;
  1187.  
  1188.                 if(Dest)
  1189.                 {
  1190.                     if(BufCnt++ < (BUFSIZ - 1))
  1191.                         *Dest++ = TmpC;
  1192.                     else
  1193.                         break;
  1194.                 }
  1195.  
  1196.                 if(TmpC == Delim)
  1197.                     DeliCnt++;
  1198.                 elif(TmpC == mileD)
  1199.                     DeliCnt--;
  1200.                 elif(!TmpC)
  1201.                     break;
  1202.             }
  1203.             if(Dest)
  1204.                 *--Dest = 0L;
  1205.             Retval = ++Buf;
  1206.         }
  1207.         else if(TmpC)
  1208.         {
  1209.             if(Dest)
  1210.             {
  1211.                 Dest[0] = TmpC;
  1212.                 Dest[1] = 0L;
  1213.             }
  1214.             Retval = ++Buf;
  1215.         }
  1216.     }
  1217.     return(Retval);
  1218. }
  1219.  
  1220. #define PRINT_MESSAGE   va_start(MsgArgs, Error);   \
  1221. vfprintf(OutputFile, LaTeXMsgs[Error].Message, MsgArgs); \
  1222. va_end(MsgArgs)
  1223.  
  1224.  
  1225. /*
  1226.  * Uses OutputFormat. Be sure that `String'
  1227.  * does not contain tabs, newlines, etc.
  1228.  * Prints a formatted string. Formatting codes understood:
  1229.  *  %b  - string to print Between fields (from -s option)
  1230.  *  %c  - Column position of error
  1231.  *  %d  - lenght of error (Digit)
  1232.  *  %f  - current Filename
  1233.  *  %i  - Turn on inverse printing mode.
  1234.  *  %I  - Turn off inverse printing mode.
  1235.  *  %k  - Kind of error (warning, error, message)
  1236.  *  %l  - Line number of error
  1237.  *  %m  - warning Message
  1238.  *  %n  - warning Number
  1239.  *  %u  - an Underlining line (like the one which appears when using -v1)
  1240.  *  %r  - part of line in front of error ('S' - 1)
  1241.  *  %s  - part of line which contains error (String) *  %t  - part of line after error ('S' + 1)
  1242.  */
  1243.  
  1244.  
  1245. void  PrintError(const  STRPTR  File,   const  STRPTR String,
  1246.                  const LONG Position,   const LONG Len,
  1247.                  const LONG Line, const enum ErrNum Error, ...)
  1248. {
  1249.     static      /* Just to reduce stack usage... */
  1250.         UBYTE   PrintBuffer[BUFSIZ];
  1251.     va_list     MsgArgs;
  1252.  
  1253.     STRPTR      LastNorm = OutputFormat,
  1254.                 of = OutputFormat;
  1255.     int         c;
  1256.  
  1257.     enum Context Context;
  1258.  
  1259.     if(betw(emMinFault, Error, emMaxFault) && LaTeXMsgs[Error].InUse)
  1260.     {
  1261.         do
  1262.         {
  1263.             Context  = LaTeXMsgs[Error].Context;
  1264.  
  1265.             if(!HeadErrOut)
  1266.                 Context |= ctOutHead;
  1267.  
  1268. #define RGTCTXT(Ctxt, Var) if((Context & Ctxt) && !(Var)) break;
  1269.  
  1270.             RGTCTXT(ctInMath, MathMode);
  1271.             RGTCTXT(ctOutMath, !MathMode);
  1272.             RGTCTXT(ctInHead, InHeader);
  1273.             RGTCTXT(ctOutHead, !InHeader);
  1274.  
  1275.             switch(LaTeXMsgs[Error].Type)
  1276.             {
  1277.             case etWarn:
  1278.                 WarnPrint++;
  1279.                 break;
  1280.             case etErr:
  1281.                 ErrPrint++;
  1282.                 break;
  1283.             case etMsg:
  1284.                 break;
  1285.             }
  1286.  
  1287.             while((of = strchr(LastNorm, '%')))
  1288.             {
  1289.                 c = *of;
  1290.                 *of = 0;
  1291.  
  1292.                 fputs(LastNorm, OutputFile);
  1293.  
  1294.                 *of++ = c;
  1295.  
  1296.                 switch(c = *of++)
  1297.                 {
  1298.                 case 'b':
  1299.                     fputs(Delimit, OutputFile);
  1300.                     break;
  1301.                 case 'c':
  1302.                     fprintf(OutputFile, "%ld", Position + 1);
  1303.                     break;
  1304.                 case 'd':
  1305.                     fprintf(OutputFile, "%ld", Len);
  1306.                     break;
  1307.                 case 'f':
  1308.                     fputs(File, OutputFile);
  1309.                     break;
  1310.                 case 'i':
  1311.                     fputs(PRE_ERROR_STR, OutputFile);
  1312.                     break;
  1313.                 case 'I':
  1314.                     fputs(POST_ERROR_STR, OutputFile);
  1315.                     break;
  1316.                 case 'k':
  1317.                     switch(LaTeXMsgs[Error].Type)
  1318.                     {
  1319.                     case etWarn:
  1320.                         fprintf(OutputFile, "Warning");
  1321.                         break;
  1322.                     case etErr:
  1323.                         fprintf(OutputFile, "Error");
  1324.                         break;
  1325.                     case etMsg:
  1326.                         fprintf(OutputFile, "Message");
  1327.                         break;
  1328.                     }
  1329.                     break;
  1330.                 case 'l':
  1331.                     fprintf(OutputFile, "%ld", Line);
  1332.                     break;
  1333.                 case 'm':
  1334.                     PRINT_MESSAGE;
  1335.                     break;
  1336.                 case 'n':
  1337.                     fprintf(OutputFile, "%d", Error);
  1338.                     break;
  1339.                 case 'u':
  1340.                     sfmemset(PrintBuffer, ' ', (LONG) Position);
  1341.  
  1342.                     sfmemset(&PrintBuffer[Position], '^', Len);
  1343.                     PrintBuffer[Position + Len] = 0;
  1344.                     fputs(PrintBuffer, OutputFile);
  1345.                     break;
  1346.                 case 'r':
  1347.                     strmid(String, PrintBuffer, 0L, Position);
  1348.                     fputs(PrintBuffer, OutputFile);
  1349.                     break;
  1350.                 case 's':
  1351.                     strmid(String, PrintBuffer, Position, Len);
  1352.                     fputs(PrintBuffer, OutputFile);
  1353.                     break;
  1354.                 case 't':
  1355.                     strmid(String, PrintBuffer, Position + Len, LONG_MAX);
  1356.                     fputs(PrintBuffer, OutputFile);
  1357.                     break;
  1358.                 default:
  1359.                     fputc(c, OutputFile);
  1360.                     break;
  1361.                 }
  1362.                 LastNorm = of;
  1363.             }
  1364.             fputs(LastNorm, OutputFile);
  1365.  
  1366.         } while(FALSE);
  1367.     }
  1368.     else
  1369.         UserSupp++;
  1370.  
  1371. }
  1372. #undef PRINT_MESSAGE
  1373.  
  1374. /*
  1375.  * All commands isolated is routed through this command, so we can
  1376.  * update global statuses like math mode and whether @ is a letter
  1377.  * or not.
  1378.  */
  1379.  
  1380. enum ErrNum PerformCommand(const STRPTR Cmd, STRPTR Arg)
  1381. {
  1382.     STRPTR Argument = "";
  1383.     enum ErrNum
  1384.         en = emMinFault;
  1385.  
  1386.     if(HasWord(Cmd, &Italic))
  1387.         ItState = itOn;
  1388.     elif(!strcmp(Cmd, "\\makeatletter"))
  1389.         AtLetter = TRUE;
  1390.     elif(!strcmp(Cmd, "\\makeatother"))
  1391.         AtLetter = FALSE;
  1392.     elif(InputFiles && !(strcmp(Cmd, "\\input") && strcmp(Cmd, "\\include")))
  1393.     {
  1394.         Arg = strip(Arg, STRP_LFT);
  1395.         if(*Arg == '{') /* } */
  1396.         {
  1397.             if(GetLTXArg(Arg, TmpBuffer, '{'))  /* } */
  1398.                 Argument = TmpBuffer;
  1399.         }
  1400.         else
  1401.             Argument = strip(Arg, STRP_BTH);
  1402.  
  1403.         ifn(Argument && PushFileName(Argument, &InputStack))
  1404.             en = emNoCmdExec;
  1405.     }
  1406.     elif(*Cmd == '\\')
  1407.     {
  1408.         /* Quicker check of single lettered commands. */
  1409.         switch(Cmd[1])
  1410.         {
  1411.         case '(':
  1412.         case '[':
  1413.             MathMode = TRUE;
  1414.             break;
  1415.         case ']':
  1416.         case ')':
  1417.             MathMode = FALSE;
  1418.             break;
  1419.         case '/':
  1420.             switch(ItState)
  1421.             {
  1422.             case itOn:
  1423.                 ItState = itCorrected;
  1424.                 Argument = Arg;
  1425.  
  1426.                 while(*Argument++ == '}')
  1427.                     ;
  1428.                 Argument--;
  1429.  
  1430.                 if(strchr(".,", *Argument))
  1431.                     en = emItPunct;
  1432.  
  1433.                 break;
  1434.             case itCorrected:
  1435.                 en = emItDup;
  1436.                 break;
  1437.             case itOff:
  1438.                 en = emItInNoIt;
  1439.             }
  1440.             break;
  1441.         }
  1442.     }
  1443.     return(en);
  1444. }
  1445.  
  1446.  
  1447.  
  1448.  
  1449.